//========================================================//
// Socket Lib                                             //
// Basic classes ans interfaces                           //
// Author: Bezdolnyj Alexey aka BAM  bamalex@ngs.ru       //
// NSU FIT May-July 2004                                  //
//========================================================//

#include "packet.h"

namespace BAM
{
	//=========================== cPacketData =======================================

	void cPacketData::resize(dword nSize, bool fromEnd)
	{
		if(nSize == vSize)
			return;
		byte *N;
		if(nSize)
			N = new byte[nSize];
		else N = 0;
		if(vData)
		{
			dword L = (nSize < vSize?nSize:vSize);
			if(fromEnd)
				memcpy(N + nSize - L, vData + vSize - L, L);
			else memcpy(N, vData, L);
			if(vOwn)
				delete[] vData;
			else vOwn = true;
		}
		vData = N;
		vSize = nSize;
	}

	cPacketData::cPacketData()
	{
		vLocks = 0;
		vData = 0;
		vSize = 0;
		vLength = 0;
		vOwn = true;
	}

	cPacketData::cPacketData(const cPacketData &Pd)
	{
		vLocks = 0;
		vSize = Pd.vLength;
		vLength = Pd.vLength;
		vData = new byte[vSize];
		vOwn = true;
		memcpy(vData, Pd.vData, vSize);
	}

	cPacketData::cPacketData(dword Size)
	{
		vLocks = 0;
		vSize = Size;
		vLength = 0;
		vData = new byte[vSize];
		vOwn = true;
	}

	cPacketData::cPacketData(const byte *Buf, dword Len)
	{
		vLocks = 0;
		vSize = Len;
		vLength = Len;
		vData = new byte[Len];
		memcpy(vData, Buf, Len);
		vOwn = true;
	}

	cPacketData::cPacketData(byte *Buf, dword Len, bool Own)
	{
		vLocks = 0;
		vSize = Len;
		vLength = Len;
		vData = Buf;
		vOwn = Own;
	}

	cPacketData::~cPacketData()
	{
		//cout << "Real destructor for cPacketData at " << hex << this << dec << endl;
		if(vData && vOwn)
		{
			//cout << "Deleting bytes at " << hex << (void*)vData << dec << endl;
			delete[] vData;
		}
	}

	bool cPacketData::operator == (const cPacketData &Pd)
	{
		if(Pd.getLength() != getLength())
			return false;
		return !memcmp(getData(), Pd.getData(), getLength());
	}

	dword cPacketData::lock()
	{
		return(++vLocks);
	}

	dword cPacketData::unlock()
	{
		if(!vLocks)
			return 0;
		return(--vLocks);
	}

	dword cPacketData::usage() const
	{
		return (vLocks + (!vOwn?1:0));
	}

	void cPacketData::insertHeader(const byte *Buf, dword Len)
	{
		if(vLength + Len > vSize)
			resize(vLength + Len);
		memmove(vData + Len , vData, vLength);
		memcpy(vData, Buf, Len);
		vLength += Len;
	}

	void cPacketData::insertTail(const byte *Buf, dword Len)
	{
		if(vLength + Len > vSize)
			resize(vLength + Len);
		memcpy(vData + vLength, Buf, Len);
		vLength += Len;
	}

	void cPacketData::removeHeader(dword Len)
	{
		if(Len >= vLength)
		{
			vLength = 0;
			return;
		}
		memmove(vData, vData + Len, vLength - Len);
		removeTail(Len);
	}

	void cPacketData::write(const byte *Buf, dword Len, dword Pos)
	{
		if(Pos + Len > vLength)
			throw EXC_BadMem;
		memcpy(vData + Pos, Buf, Len);
	}

	void cPacketData::fill(byte B, dword Len, dword Pos)
	{
		if(Pos + Len > vLength)
			throw EXC_BadMem;
		memset(vData + Pos, B, Len);
	}

	void cPacketData::read(byte *Buf, dword Len, dword Pos) const
	{
		if(Pos + Len > vLength)
			throw EXC_BadMem;
		memcpy(Buf, vData + Pos, Len);
	}

	dword cPacketData::setRealSize(dword nSize)
	{
		if((nSize == 0) && vData)
		{
			if(vOwn)
				delete[] vData;
			vData = 0;
			vSize = 0;
			vLength = 0;
			return vSize;
		}
		resize(nSize);
		if(nSize < vLength)
			vLength = nSize;
		return vSize;
	}

	dword cPacketData::setLength(dword nLen)
	{
		if(nLen > vSize)
			resize(nLen);
		vLength = nLen;
		return vLength;
	}

	//=========================== cPacket =======================================

	cPacket::cPacket()
	{
		vPData = new cPacketData();
		vPData->lock();
	}

	cPacket::cPacket(const cPacket &P)
	{
		vPData = P.vPData;
		vPData->lock();
	}

	cPacket::cPacket(dword Size)
	{
		vPData = new cPacketData(Size);
		vPData->lock();
	}

	cPacket::cPacket(const byte *Buf, dword Len)
	{
		vPData = new cPacketData(Buf, Len);
		vPData->lock();
	}

	cPacket::cPacket(byte *Buf, dword Len, bool Own)
	{
		vPData = new cPacketData(Buf, Len, Own);
		vPData->lock();
	}

	void cPacket::release()
	{
		if(!vPData->unlock())
		{
			//			cout << "Destructor for cPacketData at " << hex << vPData << dec << endl;
			//			DBG_PrintPacket(*this);
			delete vPData;
		}
	}

	cPacket::~cPacket()
	{
		//		cout << "Destructor for cPacket at " << hex << this << dec << endl;
		release();
	}

	cPacket& cPacket::operator = (const cPacket &P)
	{
		if (this == &P)
			return *this;
		release();
		vPData = P.vPData;
		vPData->lock();
		return *this;
	}

	void cPacket::clear()
	{
		if(vPData->usage() > 1)
		{
			release();
			vPData = new cPacketData();
			vPData->lock();
		}
		else
			vPData->setLength(0);
	}

	void cPacket::insertHeader(const byte *Buf, dword Len)
	{
		copyifusage();
		vPData->insertHeader(Buf, Len);
	}

	void cPacket::insertTail(const byte *Buf, dword Len)
	{
		copyifusage();
		vPData->insertTail(Buf, Len);
	}

	void cPacket::removeHeader(dword Len)
	{
		copyifusage();
		vPData->removeHeader(Len);
	}

	void cPacket::removeTail(dword Len)
	{
		copyifusage();
		vPData->removeTail(Len);
	}

	dword cPacket::setLength(dword nLen)
	{
		if(nLen == vPData->getLength())
			return nLen;
		copyifusage();
		return vPData->setLength(nLen);
	}

	dword cPacket::setRealSize(dword nSize)
	{
		if(nSize < vPData->getRealSize())
			copyifusage();
		return vPData->setRealSize(nSize);
	}

	byte* cPacket::getWData()
	{
		copyifusage();
		return vPData->getWData();
	}

	void cPacket::write(const byte *Buf, dword Len, dword Pos)
	{
		copyifusage();
		vPData->write(Buf, Len, Pos);
	}

#ifdef _BAM_DEBUG	
	void DBG_PrintPacket(const cPacket &P)
	{
		cout << "-----------------------------------------------" << endl;
		for(dword i = 0; i < P.getLength(); i++)
		{
			if (i && !(i%16)) cout << endl;
			if ((unsigned int)(P.getData())[i] < 16)
				cout << hex << "0";
			cout << hex << uppercase << (unsigned int)(P.getData())[i] << " ";
		}
		cout << endl << "-----------------------------------------------" << endl << dec << endl;
	}
#endif


}
